package b.sync

import cats.effect._
import cats.implicits._
import doobie.implicits._
import doobie.util.update.Update
import doobie.{ConnectionIO, Read, _}
import eu.timepit.refined.auto._

package object domain {
  implicit class DbRowOps(op: String) {
    def retrieve[B: Read](from: Long, rows: Long = 5): ConnectionIO[List[B]] = {
      val frFrom = Some(fr"sync_row_no > $from")
      val parts = op.split(" WHERE ")
      val heads = parts.head.split(" FROM ")
      val base = heads.head + ", x.sync_row_no, x.sync_op_type FROM " + heads.last
      val frBase = Fragment.const(base)
      val frWhere = if (parts.length == 1) None else Some(Fragment.const(parts.last))
      val frSelect = frBase ++ Fragments.whereAndOpt(frFrom, frWhere)
      frSelect.query[B].stream.take(rows).compile.toList
    }
    def execute[B: Write](rows: List[B]): ConnectionIO[Int] =
      Update[B](op).updateMany(rows)
  }
  implicit class ExtractOnOps[B: Read](q: ConnectionIO[List[B]]) {
    def on(ds: DataSource): IO[List[B]] = q.transact(xa(ds))
  }
  implicit class ReplicateOnOps(q: ConnectionIO[Int]) {
    def on(ds: DataSource): IO[Int] = q.transact(xa(ds))
  }
  private def xa(ds: DataSource) =
    Transactor.fromDriverManager[IO](ds.driver, ds.url, ds.user, ds.password)

  type TSync[R] = (R, Int, Int)
}
